package dict

import (
	"bytes"
	"context"
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	"gitee.com/igolang/imoney/internal/app/system/tools"
	commonEntities "gitee.com/igolang/imoney/internal/common/entities"
	"gitee.com/igolang/imoney/internal/common/httpResp"
	commonDict "gitee.com/igolang/imoney/internal/common/services/dict"
	commonTools "gitee.com/igolang/imoney/internal/common/tools"
	"gitee.com/igolang/imoney/internal/core/client"
	"gitee.com/igolang/imoney/internal/models/dao"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/pkg/xgorm"
	"gitee.com/igolang/pkg/xtime"
	"gitee.com/igolang/pkg/xutils"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"gorm.io/gen"
	"time"
)

var DictData = &dictData{}

type dictData struct{}

func (s *dictData) List(ctx *gin.Context) (*commonEntities.ListResp, error) {
	var req entities.DictDataPageListReq
	if err := ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	if req.DictType == "" {
		return nil, errors.New("请选择字典")
	}
	req.Page()
	conds := s.formatListConds(req)
	total, err := dao.SysDictDatum.Where(conds...).Count()
	if err != nil {
		return nil, err
	}
	result := &commonEntities.ListResp{
		Total: total,
		Rows:  make([]*model.SysDictDatum, 0),
	}
	rows, err := dao.SysDictDatum.Where(conds...).Order(dao.SysDictDatum.DictSort, dao.SysDictDatum.DictCode.Desc()).Find()
	if err != nil {
		return nil, err
	}
	result.Rows = rows
	return result, nil
}

func (s *dictData) Export(ctx *gin.Context) (b *bytes.Buffer, err error) {
	var req entities.DictDataPageListReq
	if err = ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	if req.DictType == "" {
		return nil, errors.New("请选择字典")
	}
	conds := s.formatListConds(req)
	header := []string{"字典编码", "字典排序", "字典标签", "字典键值", "字典类型", "是否默认", "状态"}
	data := [][]string{header}
	rows, err := dao.SysDictDatum.Where(conds...).Order(dao.SysDictDatum.DictSort, dao.SysDictDatum.DictCode.Desc()).Rows()
	if err = ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	dc := client.DB()
	commonStatusOptions, _ := Get("sys_normal_disable")
	for rows.Next() {
		row := &model.SysDictDatum{}
		if dc.ScanRows(rows, row) == nil {
			data = append(data, []string{
				cast.ToString(row.DictCode),
				cast.ToString(row.DictSort),
				row.DictLabel,
				row.DictValue,
				row.DictType,
				row.IsDefault,
				LabelOptions(commonStatusOptions, row.Status),
			})
		}
	}
	fh := xutils.CreateExcelFileWithData(data)
	defer fh.Close()
	b, err = fh.WriteToBuffer()
	return
}

func (s *dictData) Save(ctx *gin.Context) (err error) {
	req := &model.SysDictDatum{}
	if err = ctx.ShouldBindJSON(req); err != nil {
		return err
	}
	if req.DictLabel == "" || req.DictValue == "" || req.DictType == "" {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	if req.Status == "" {
		req.Status = constants.OkStatus
	}
	if req.IsDefault == "" {
		req.IsDefault = "N"
	}
	userInfo := tools.GetUserInfo(ctx)
	req.UpdateBy = userInfo.User.UserName
	req.UpdateTime = xtime.Time(time.Now())
	if req.DictCode == 0 {
		req.CreateBy = userInfo.User.UserName
		req.CreateTime = xtime.Time(time.Now())
		return dao.SysDictDatum.Create(req)
	}
	row, err := dao.SysDictDatum.Where(dao.SysDictDatum.DictCode.Eq(req.DictCode)).Take()
	if err != nil {
		return err
	}
	row.UpdateTime = req.UpdateTime
	row.UpdateBy = req.UpdateBy
	row.Remark = req.Remark
	row.DictType = req.DictType
	row.Status = req.Status
	row.DictLabel = req.DictLabel
	row.DictValue = req.DictValue
	row.DictSort = req.DictSort
	row.CSSClass = req.CSSClass
	row.ListClass = req.ListClass
	data := xgorm.ModelToMap(row)
	_, err = dao.SysDictDatum.Where(dao.SysDictDatum.DictCode.Eq(req.DictCode)).Updates(data)
	if err == nil {
		s.setCache(req.DictType)
	}
	return
}

func (s *dictData) Delete(ctx *gin.Context) (err error) {
	ids := commonTools.String2Int64s(ctx.Param("ids"))
	if len(ids) == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	rows, err := dao.SysDictDatum.Select(dao.SysDictDatum.DictType).Where(dao.SysDictDatum.DictCode.In(ids...)).Find()
	if err != nil {
		return err
	}
	if len(rows) == 0 {
		return nil
	}
	_, err = dao.SysDictDatum.Where(dao.SysDictDatum.DictCode.In(ids...)).Delete()
	if err != nil {
		return err
	}
	xutils.RecoverGo(func() {
		for _, v := range rows {
			s.setCache(v.DictType)
		}
	}, commonTools.ErrorHandler(context.Background(), "删除字典数据，更新字典缓存"))
	return
}

func (s *dictData) formatListConds(req entities.DictDataPageListReq) []gen.Condition {
	conds := make([]gen.Condition, 0)
	if req.DictType != "" {
		conds = append(conds, dao.SysDictDatum.DictType.Eq(req.DictType))
	}

	if req.DictLabel != "" {
		conds = append(conds, dao.SysDictDatum.DictLabel.Like(`%`+req.DictLabel+`%`))
	}

	if req.Status != "" {
		conds = append(conds, dao.SysDictDatum.Status.Eq(req.Status))
	}

	return conds
}

func (s *dictData) setCache(t string) []*model.SysDictDatum {
	return commonDict.DictData.SetCache(t)
}

func (s *dictData) cleanCache(t string) {
	commonDict.DictData.CleanCache(t)
}
